package the.workshop.bu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.wisteria.framework.util.TreeSelected;
import the.broccoli.setting.service.IDictService;
import the.broccoli.setting.service.IParamsService;
import the.workshop.bu.entity.Product;
import the.workshop.bu.entity.ProductArea;
import the.workshop.bu.entity.ProductRule;
import the.workshop.bu.mapper.ProductAreaMapper;
import the.workshop.bu.mapper.ProductMapper;
import the.workshop.bu.mapper.ProductRuleMapper;
import the.workshop.bu.service.IProductService;
import org.wisteria.framework.web.mvc.service.AbstractSuperService;
import org.springframework.stereotype.Service;
import the.workshop.bu.service.dto.*;
import the.workshop.bu.service.support.ProductMatchSupport;
import the.workshop.bu.service.support.ProductSearchSupport;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 产品 服务实现类
 * </p>
 *
 * @author lei.liu
 * @since 2020-06-24
 */
@Service
public class ProductServiceImpl extends AbstractSuperService<ProductMapper, Product> implements IProductService {

    @Resource
    private ProductAreaMapper productAreaMapper;

    @Resource
    private ProductRuleMapper productRuleMapper;

    @Resource
    private ProductSearchSupport productSearchSupport;

    @Resource
    private ProductMatchSupport productMatchSupport;

    @Resource
    private IDictService dictService;

    @Resource
    private IParamsService paramsService;

    @Override
    public List<ProductSearchResultDTO> search(ProductSearchConditionDTO dto) {
        return productSearchSupport.search(dto);
    }

    @Override
    public boolean save(ProductSaveDTO dto) {

        Product product = new Product();
        BeanUtils.copyProperties(dto, product);
        product.setCreatedTime(new Date());
        product.setCreatedId(dto.getOperatorId());
        product.setCreatedName(dto.getOperatorName());
        product.setModifiedTime(new Date());
        product.setModifiedId(dto.getOperatorId());
        product.setModifiedName(dto.getOperatorName());
        baseMapper.insert(product);

        if (!CollectionUtils.isEmpty(dto.getRuleIdList())) {
            ProductRule productRule = null;
            for (String ruleId : dto.getRuleIdList()) {
                productRule = new ProductRule();
                productRule.setProductId(product.getId());
                productRule.setRuleId(ruleId);
                productRule.setCreatedTime(new Date());
                productRule.setCreatedId(dto.getOperatorId());
                productRule.setCreatedName(dto.getOperatorName());
                productRule.setModifiedTime(new Date());
                productRule.setModifiedId(dto.getOperatorId());
                productRule.setModifiedName(dto.getOperatorName());
                productRuleMapper.insert(productRule);
            }
        }

        if (!CollectionUtils.isEmpty(dto.getAreaList())) {
            ProductArea productArea = null;
            for (ProductSaveDTO.Area area : dto.getAreaList()) {
                productArea = new ProductArea();
                productArea.setProductId(product.getId());
                productArea.setProvinceId(area.getProvinceId());
                productArea.setCityId(area.getCityId());
                productArea.setCreatedTime(new Date());
                productArea.setCreatedId(dto.getOperatorId());
                productArea.setCreatedName(dto.getOperatorName());
                productArea.setModifiedTime(new Date());
                productArea.setModifiedId(dto.getOperatorId());
                productArea.setModifiedName(dto.getOperatorName());
                productAreaMapper.insert(productArea);
            }
        }

        return true;
    }

    @Override
    public boolean updateById(ProductModifyDTO dto) {
        Product product = new Product();
        BeanUtils.copyProperties(dto, product);
        product.setId(dto.getProductId());
        product.setModifiedTime(new Date());
        product.setModifiedId(dto.getOperatorId());
        product.setModifiedName(dto.getOperatorName());
        baseMapper.updateById(product);
        return true;
    }

    @Override
    public boolean updateProductRule(ProductRuleModifyDTO dto) {
        productRuleMapper.update(null, new LambdaUpdateWrapper<ProductRule>()
                .set(ProductRule::getIsDeleted, 1)
                .set(ProductRule::getModifiedTime, new Date())
                .set(ProductRule::getModifiedId, dto.getOperatorId())
                .set(ProductRule::getModifiedName, dto.getOperatorName())
                .eq(ProductRule::getProductId, dto.getProductId())
        );
        if (!CollectionUtils.isEmpty(dto.getRuleIdList())) {
            ProductRule productRule = null;
            for (String ruleId : new HashSet<>(dto.getRuleIdList())) {
                productRule = new ProductRule();
                productRule.setProductId(dto.getProductId());
                productRule.setRuleId(ruleId);
                productRule.setCreatedTime(new Date());
                productRule.setCreatedId(dto.getOperatorId());
                productRule.setCreatedName(dto.getOperatorName());
                productRule.setModifiedTime(new Date());
                productRule.setModifiedId(dto.getOperatorId());
                productRule.setModifiedName(dto.getOperatorName());
                productRuleMapper.insert(productRule);
            }
        }
        return true;
    }

    @Override
    public boolean updateProductArea(ProductAreaModifyDTO dto) {
        productAreaMapper.update(null, new LambdaUpdateWrapper<ProductArea>()
                .set(ProductArea::getIsDeleted, 1)
                .set(ProductArea::getModifiedTime, new Date())
                .set(ProductArea::getModifiedId, dto.getOperatorId())
                .set(ProductArea::getModifiedName, dto.getOperatorName())
                .eq(ProductArea::getProductId, dto.getProductId())
        );

        if (!CollectionUtils.isEmpty(dto.getAreaList())) {
            ProductArea productArea = null;
            for (ProductAreaModifyDTO.Area area : dto.getAreaList()) {
                productArea = new ProductArea();
                productArea.setProductId(dto.getProductId());
                productArea.setProvinceId(area.getProvinceId());
                productArea.setCityId(area.getCityId());
                productArea.setCreatedTime(new Date());
                productArea.setCreatedId(dto.getOperatorId());
                productArea.setCreatedName(dto.getOperatorName());
                productArea.setModifiedTime(new Date());
                productArea.setModifiedId(dto.getOperatorId());
                productArea.setModifiedName(dto.getOperatorName());
                productAreaMapper.insert(productArea);
            }
        }
        return true;
    }

    @Override
    public ProductGetDTO getDetailById(Integer productId) {
        Product product = baseMapper.selectById(productId);
        if (product == null) {
            return null;
        }

        ProductGetDTO dto = new ProductGetDTO();
        BeanUtils.copyProperties(product, dto);
        dto.setProductId(product.getId());
        dto.setQrFileName(product.getQr());
        dto.setQr(paramsService.getValue("bu.image.host") + "/" + dto.getQr());

        List<ProductRule> productRuleList = productRuleMapper.selectList(new LambdaQueryWrapper<ProductRule>()
                .eq(ProductRule::getProductId, productId)
        );
        if (!CollectionUtils.isEmpty(productRuleList)) {
            dto.setRuleIdList(productRuleList.stream().map(ProductRule::getRuleId).collect(Collectors.toList()));
        }

        List<ProductArea> productAreaList = productAreaMapper.selectList(new LambdaQueryWrapper<ProductArea>()
                .eq(ProductArea::getProductId, productId)
        );
        if (!CollectionUtils.isEmpty(productAreaList)) {
            dto.setAreaList(productAreaList.stream().map(this::convertOf).collect(Collectors.toList()));
        }

        return dto;
    }

    @Override
    public TreeSelected getProductRuleTreeSelected(Integer productId) {
        return dictService.getTreeSelected("product_rule", getProductRuleIdList(productId));
    }

    @Override
    public TreeSelected getProductAreaTreeSelected(Integer productId) {
        return dictService.getTreeSelected("region", getProductAreaIdList(productId));
    }

    @Override
    public List<ProductMatchResultDTO> matchProduct(ProductMatchDTO dto) {
        return productMatchSupport.matchProduct(dto);
    }

    private List<String> getProductRuleIdList(Integer productId) {
        List<ProductRule> productRuleList = productRuleMapper.selectList(new LambdaQueryWrapper<ProductRule>()
                .eq(ProductRule::getProductId, productId)
        );
        return CollectionUtils.isEmpty(productRuleList) ? null : productRuleList.stream().map(ProductRule::getRuleId).collect(Collectors.toList());
    }

    private List<String> getProductAreaIdList(Integer productId) {
        List<ProductArea> productAreaList = productAreaMapper.selectList(new LambdaQueryWrapper<ProductArea>()
                .eq(ProductArea::getProductId, productId)
        );
        if (CollectionUtils.isEmpty(productAreaList)) {
            return null;
        }

        Set<String> areaIdList = new HashSet<>();
        for (ProductArea area : productAreaList) {
            areaIdList.add(area.getProvinceId());
            areaIdList.add(area.getCityId());
        }
        return new ArrayList<>(areaIdList);
    }

    private ProductGetDTO.Area convertOf(ProductArea source) {
        ProductGetDTO.Area target = new ProductGetDTO.Area();
        target.setProvinceId(source.getProvinceId());
        target.setCityId(source.getCityId());
        return target;
    }
}
